/**
 *  @author 侯庆峰, 15/12/16.
 *
 *  @name LTHttpOperation.cpp
 *
 *  @brief.
 *
 *  @copyright © 2015年 letv. All rights reserved.
 */
#include "LTHttpOperation.h"
#include <algorithm>

int LTHttpOperation::requestID = 0;

/**
 *  构造函数
 */
LTHttpOperation::LTHttpOperation()
: isDeleted(false)
, context(NULL)
, InitState(true)
, bufferData(NULL)
, bufferDataLength(0)
, curl(NULL)
, url(NULL)
, timeout(60)
, headerList(NULL)
, callBack(NULL)
, postData(NULL)
, postDataLength(0)
, proxy(NULL)
{
    ;
}

/**
 *  get Request
 */
CurlRequestHandler LTHttpOperation::GetRequest(const char *url,
                                               long urlLength,
                                               long timeout,
                                               map<string, string> &httpheader,
                                               void *context,
                                               char *proxy,
                                               long proxyLength,
                                               LTCurlCallback callc)
{
    this->requestType = getRequest;
    this->SetCommonParamter(url, urlLength, timeout, httpheader,
                            context, proxy, proxyLength, callc);
    this->SetCurlParameter();
    return this->SetRequestID();
}

/**
 *  post Request
 */
CurlRequestHandler LTHttpOperation::PostRequest(const char *url,
                                                long urlLength,
                                                long timeout,
                                                map<string, string> &httpheader,
                                                void *context,
                                                void *postdata,
                                                long postlength,
                                                char *proxy,
                                                long proxyLength,
                                                LTCurlCallback callc)
{
    this->requestType = postRequest;
    this->SetCommonParamter(url, urlLength, timeout, httpheader,
                            context, proxy, proxyLength, callc);
    this->SetPostDataLength(postlength);
    this->SetPostData(postdata,postlength);
    this->SetCurlParameter();
    return this->SetRequestID();
}

/**
 *  设置通用参数
 */
void LTHttpOperation::SetCommonParamter(const char *url,
                                        long urlLength,
                                        long timeout,
                                        map<string, string> &httpheader,
                                        void *context,
                                        char *proxy,
                                        long proxyLength,
                                        LTCurlCallback callc)
{
    this->InitCurl();
    this->SetUrl((char*)(url), urlLength);
    this->SetTimeout(timeout);
    this->SetHttpHeader(httpheader);
    this->SetContext(context);
    this->setProxy(proxy, proxyLength);
    this->SetCallBack(callc);
}

/**
 * 初始化curl
 */
bool LTHttpOperation::InitCurl()
{
    this->curl = curl_easy_init();
    
    if (this->curl) {
        return true;
    }
    
    return  false;
}

CURL *LTHttpOperation::GetCurl()
{
    return this->curl;
}

/**
 *  设置context
 */
void LTHttpOperation::SetContext(void *context)
{
    this->context = context;
}

void *LTHttpOperation::GetContext()
{
    return this->context;
}

/**
 *  设置url
 */
bool LTHttpOperation::SetUrl(char *url, long length)
{
    if (!url && length <= 0) {
        this->InitState = false;
        this->url = NULL;
        return false;
    }
    
    this->url = new char[length + 1];
    this->url[length] = '\0';
    if (!this->url) {
        return NULL;
    }
    
    memcpy(this->url, url, length);
    return true;
}

char *LTHttpOperation::GetUrl()
{
    return this->url;
}

/**
 *  设置timeout
 */
bool LTHttpOperation::SetTimeout(long timeout)
{
    if (timeout <= 0) {
        this->InitState = false;
        this->timeout = 60;//默认时间
        return false;
    }
    
    this->timeout = timeout;
    return true;
}

long LTHttpOperation::GetTimeout()
{
    return this->timeout;
}

/**
 *  设置httpheader
 */
bool LTHttpOperation::SetHttpHeader(map<string, string> &httpheader)
{
    if (httpheader.empty()) {
        return false;
    }
    
    map<string, string>::iterator ite = httpheader.begin();
    for (; ite != httpheader.end(); ++ite) {
        httpHeader.insert(make_pair(ite->first, ite->second));
    }
    
    return true;
}

struct curl_slist *LTHttpOperation::GetHttpHeader()
{
    this->headerList = NULL;
    
    if (httpHeader.empty()) {
        return this->headerList;
    }
    
    map<string, string>::iterator iter = this->httpHeader.begin();
    for (; iter != this->httpHeader.end(); ++iter){
        string str = "";
        str = iter->first + ": " + iter->second;
        this->headerList = curl_slist_append(this->headerList, str.c_str());
        str = "";
    }
    
    return this->headerList;
}

/**
 * 设置postdata
 */
void LTHttpOperation::SetPostData(void *postdata,long postlength)
{
    char *ch = (char*)postdata;
    if (!ch && this->postDataLength < 0) {
        this->postData = NULL;
        return;
    }
    this->postData = new char[this->postDataLength];
    if (!this->postData) {
        return;
    }
    memcpy(this->postData, postdata, this->postDataLength);
}

void *LTHttpOperation::GetPostData()
{
    return this->postData;
}

/**
 *  设置postdata length
 */
bool LTHttpOperation::SetPostDataLength(long postlength)
{
    if (postlength < 0) {
        this->InitState = false;
        this->postDataLength = 0;
    }
    this->postDataLength = postlength;
    return true;
}

long LTHttpOperation::GetPostDataLength()
{
    return this->postDataLength;
}

/**
 *  设置代理
 */
void LTHttpOperation::setProxy(char *proxy, long length)
{
    if (!proxy && length > 0) {
        return;
    }
    
    this->proxy = new char[length + 1];
    this->proxy[length] = '\0';
    if (!this->proxy) {
        return;
    }
    memcpy(this->proxy, proxy, length);
}

char *LTHttpOperation::getProxy()
{
    return this->proxy;
}

/**
 *  设置回调
 */
bool LTHttpOperation::SetCallBack(LTCurlCallback callc)
{
    if (!callc) {
        this->callBack = NULL;
        this->InitState = false;
        return false;
    }
    
    this->callBack = callc;
    return true;
}

LTCurlCallback &LTHttpOperation::GetCallBack()
{
    return this->callBack;
}

/**
 *  设置curl参数
 */
void LTHttpOperation::SetCurlParameter()
{
    if (!this->curl) {
        return;
    };
    
    this->SetCurlCommonParameter();
    switch (this->requestType) {
        case getRequest:
            break;
        case postRequest:
            curl_easy_setopt(curl, CURLOPT_POST, 1);
            curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postData);
            curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, postDataLength);
        default:
            break;
    }
}


/**
 *  设置curl通用参数
 */
void LTHttpOperation::SetCurlCommonParameter()
{
    curl_easy_setopt(curl, CURLOPT_URL, url);//设置url地址
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);//设置超时时间
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 0); //是否打印信息
    curl_easy_setopt(curl, CURLOPT_HEADER, 0); //是否显示http报文头
    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);//连接是否跳转
    curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);//禁用域名解析超时
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlCallc);//回调函数
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, this);
    curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, 60 * 100);
    curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, false);
    curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, false);
    if (this->getProxy()) {
        curl_easy_setopt(curl, CURLOPT_PROXY, this->getProxy());//设置代理服务器
    }
    if (this->GetHttpHeader()) {
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, this->GetHttpHeader());//设置http头
    }
    
}

/**
 *  curl 回调
 */
size_t LTHttpOperation::curlCallc(void *buffer, size_t size, size_t length, void *context)
{
    LTHttpOperation *operation = (LTHttpOperation*)context;
    
    if (!operation) {
        return size * length;
    }
    
    char *bufferTemp = NULL;
    if (operation->bufferDataLength != 0) {
        bufferTemp = new char[operation->bufferDataLength + 1];
        bufferTemp[operation->bufferDataLength] = '\0';
        
        if (bufferTemp) {
            memcpy(bufferTemp, operation->bufferData, operation->bufferDataLength);
            if (operation->bufferData) {
                delete []operation->bufferData;
                operation->bufferData = NULL;
                
                operation->bufferData = new char[operation->bufferDataLength + (size * length) + 1];
                operation->bufferData[operation->bufferDataLength
                                      + (size * length)] = '\0'; //限定范围
                
                if (operation->bufferData) {
                    memcpy(operation->bufferData, bufferTemp, operation->bufferDataLength);
                    memcpy(operation->bufferData + operation->bufferDataLength, buffer, (size * length));
                }
            }
            
            delete []bufferTemp;
            bufferTemp = NULL;
        }
    } else { //第一次传输
        operation->bufferData = new char[size * length + 1];
        if (operation->bufferData) {
            memcpy(operation->bufferData, buffer, (size * length));
        }
        operation->bufferData[size * length] = '\0'; //限定范围
    }
    
    operation->bufferDataLength += size * length;
    return size * length;
}

/**
 *  设置request id
 */
long LTHttpOperation::SetRequestID()
{
    {
        unique_lock<mutex> guard(requestHandlerMutex);
        this->operationId = ++requestID;
    }
    
    return this->operationId;
}

inline long LTHttpOperation::GetRequestID()
{
    return this->operationId;
}

/**
 *  get buffer
 */
inline char *LTHttpOperation::GetBufferData()
{
    return this->bufferData;
}

/**
 *  get buffer length
 */
inline size_t LTHttpOperation::GetBufferDataLength()
{
    return this->bufferDataLength;
}

/**
 *  cnacel request
 */
bool LTHttpOperation::CancelRequest()
{
    return true;
}

/**
 *  设置删除标志
 */
inline void LTHttpOperation::SetIsDeleted()
{
    this->isDeleted = true;
}

inline bool LTHttpOperation::GetIsDeleted()
{
    return this->isDeleted;
}

/**
 *  析构函数
 */
LTHttpOperation::~LTHttpOperation()
{
    if (bufferData) {
        delete []bufferData;
        bufferData = NULL;
    }
    
    if (postData) {
        char *todel = (char*)postData;
        delete []todel;
        postData = NULL;
    }
    postDataLength = 0;
    
    if (curl) {
        curl_easy_cleanup(curl);
        curl = NULL;
        
    }
    
    if (headerList) {
        delete headerList;
        headerList = NULL;
    }
    
    if (url) {
        delete []url;
        url = NULL;
    }
    
    if (postData) {
        char *ch = (char*)postData;
        delete []ch;
        ch = NULL;
    }
    
    if (proxy) {
        delete []proxy;
        proxy = NULL;
    }
}
